//
// Created by hay boy on 2022/6/19.
//

#include "CircularListWithHeader.h"

template<class T>
CircularListWithHeader<T>::CircularListWithHeader(){
    headerNode = new ChainNode<T>();
    headerNode->next = headerNode;
    Chain<T>::firstNode = ExtendedChain<T>::lastNode = nullptr;
    Chain<T>::listSize = 0;
}

template<class T>
int CircularListWithHeader<T>::indexOf(const T &theElement) const{
    headerNode->element = theElement;
    ChainNode<T>* currentNode = headerNode->next;
    int index = 0;
    while(currentNode->element!=theElement){
        currentNode = currentNode->next;
        index++;
    }
    if(currentNode==headerNode){
        return -1;
    }else{
        return index;
    }
}

template<class T>
T &CircularListWithHeader<T>::get(int theIndex) const {
    Chain<T>::checkIndex(theIndex);
    ChainNode<T>* currentNode = headerNode->next;
    for(int i = 0;i<theIndex;i++){
        currentNode = currentNode->next;
    }
    return currentNode->element;
}

template<class T>
void CircularListWithHeader<T>::erase(int theIndex) {
    Chain<T>::checkIndex(theIndex);
    ChainNode<T>* deleteNode;
    if(theIndex==0){
        deleteNode = headerNode->next;
        headerNode->next = headerNode->next->next;
    }else{
        ChainNode<T>* p = headerNode->next;
        for(int i = 0;i<theIndex-1;i++){
            p = p->next;
        }
        deleteNode = p->next;
        p->next = p->next->next;
    }
    Chain<T>::listSize--;
    delete deleteNode;
}

template<class T>
void CircularListWithHeader<T>::insert(int theIndex, const T &theElement) {
    if(theIndex<0||theIndex>Chain<T>::listSize){
        ostringstream s;
        s<<"index = "<<theIndex<<" size = "<<Chain<T>::listSize;
        throw illegalIndex(s.str());
    }
    if(theIndex==Chain<T>::listSize){
        //对于listSize==0/1时均成立
        ChainNode<T>* p = headerNode;
        for(int i = 0;i<Chain<T>::listSize;i++){
            p = p->next;
        }
        ChainNode<T>* p2 = new ChainNode<T>(theElement,headerNode);
        p->next = p2;
    }else{
        ChainNode<T>* p = headerNode;
        for(int i = 0;i<theIndex;i++){
            p = p->next;
        }
        p->next = new ChainNode<T>(theElement,p->next);
    }
    Chain<T>::listSize++;
}

template<class T>
void CircularListWithHeader<T>::output(ostream &out) const {
    for(ChainNode<T>* currentNode = headerNode->next;currentNode!=headerNode;currentNode=currentNode->next){
        out<<currentNode->element<<" ";
    }
}

template<class T>
void CircularListWithHeader<T>::clear() {
    ChainNode<T>* p = headerNode->next;
    while(p!=headerNode){
        ChainNode<T>* p2 = p->next;
        delete p;
        p = p2;
    }
    p->next = p;
    Chain<T>::listSize = 0;
}

template<class T>
void CircularListWithHeader<T>::push_back(const T &theElement) {
    ChainNode<T>* newNode = new ChainNode<T>(theElement,headerNode);
    ChainNode<T>* p = headerNode;
    for(int i = 0;i<Chain<T>::listSize;i++){
        p = p->next;
    }
    p->next = newNode;
    Chain<T>::listSize++;
}

template<class T>
CircularListWithHeader<T>::~CircularListWithHeader() {
    ChainNode<T>* p = headerNode->next;
    while(p!=headerNode){
        ChainNode<T>* p2 = p->next;
        delete p;
        p = p2;
    }
    delete p;//p = p2 = headerNode;
//    delete headerNode;
}

template<class Y>
ostream &operator<<(ostream &out, const CircularListWithHeader<Y> &x) {x.output(cout);
    x.output(cout);
    return out;
}

template<class T>
ostream &operator<<(ostream &out, const Chain<T> &x) {
    x.output(out);
    return out;
}
